/* functions.c */

#include "includes.h"

int collideBlack(board * inBoard, unsigned int mask) //lower case letters
{
  debug(1, "entering collideBlack()");
  debug(1, "exiting collideBlack()");

  return mask & inBoard->k & inBoard->q & inBoard->b & inBoard->n & inBoard->r & inBoard->p;
}

int collideWhite(board * inBoard, unsigned int mask) //CAPITAL LETTERS
{
  debug(1, "entering collideWhite()");
  debug(1, "exiting collideWhite()");

  return mask & inBoard->K & inBoard->Q & inBoard->B & inBoard->N & inBoard->R & inBoard->P;
}

int debug (int level, char * message)
{
  if (DEBUG_LEVEL >= level)
  {
    printf (message);
    printf ("\n");
  }

}

/* decodeString() - This function takes a two character string of the form
 *                  [char][digit] and the mask for that coordinate on the 
 *                  board is returned. If there is an error, 0 is returned.
 **/
unsigned int decodeString(char * stringIn)
{
  debug(1, "entering decodeString()");

  if (strlen(stringIn) != 2)
  {
    printf("Error in decodeString(), input is the wrong lenght.");
    exit(1);
  }

  debug(1, "exiting decodeString()");

  if(!strcmp(stringIn, "a1"))
    return A1;
  if(!strcmp(stringIn, "a2"))
    return A2;
  if(!strcmp(stringIn, "a3"))
    return A3;
  if(!strcmp(stringIn, "a4"))
    return A4;
  if(!strcmp(stringIn, "a5"))
    return A5;
  if(!strcmp(stringIn, "a6"))
    return A6;
  if(!strcmp(stringIn, "b1"))
    return B1;
  if(!strcmp(stringIn, "b2"))
    return B2;
  if(!strcmp(stringIn, "b3"))
    return B3;
  if(!strcmp(stringIn, "b4"))
    return B4;
  if(!strcmp(stringIn, "b5"))
    return B5;
  if(!strcmp(stringIn, "b6"))
    return B6;
  if(!strcmp(stringIn, "c1"))
    return C1;
  if(!strcmp(stringIn, "c2"))
    return C2;
  if(!strcmp(stringIn, "c3"))
    return C3;
  if(!strcmp(stringIn, "c4"))
    return C4;
  if(!strcmp(stringIn, "c5"))
    return C5;
  if(!strcmp(stringIn, "c6"))
    return C6;
  if(!strcmp(stringIn, "d1"))
    return D1;
  if(!strcmp(stringIn, "d2"))
    return D2;
  if(!strcmp(stringIn, "d3"))
    return D3;
  if(!strcmp(stringIn, "d4"))
    return D4;
  if(!strcmp(stringIn, "d5"))
    return D5;
  if(!strcmp(stringIn, "d6"))
    return D6;
  if(!strcmp(stringIn, "e1"))
    return E1;
  if(!strcmp(stringIn, "e2"))
    return E2;
  if(!strcmp(stringIn, "e3"))
    return E3;
  if(!strcmp(stringIn, "e4"))
    return E4;
  if(!strcmp(stringIn, "e5"))
    return E5;
  if(!strcmp(stringIn, "e6"))
    return E6;
}

/* erase() - This function erases any pieces that were at the mask position.
 *           obviously, you should be very careful not to erase the wrong
 *           piece. */
PIECES erase(board * inBoard, unsigned int mask)
{
  debug(1, "entering erase()");
  debug(1, "exiting erase()");

  if (inBoard->k & mask)
  {
    inBoard->k ^= mask; // XOR + assignment
    return k;
  }
  if (inBoard->q & mask)
  {
    inBoard->q ^= mask;
    return q;
  }
  if (inBoard->b & mask)
  {
    inBoard->b ^= mask;
    return b;
  }
  if (inBoard->n & mask)
  {
    inBoard->n ^= mask;
    return n;
  }
  if (inBoard->r & mask)
  {
    inBoard->r ^= mask;
    return r;
  }
  if (inBoard->p & mask)
  {
    inBoard->p ^= mask;
    return p;
  }
  if (inBoard->K & mask)
  {
    inBoard->K ^= mask;
    return K;
  }
  if (inBoard->Q & mask)
  {
    inBoard->Q ^= mask;
    return Q;
  }
  if (inBoard->B & mask)
  {
    inBoard->B ^= mask;
    return B;
  }
  if (inBoard->N & mask)
  {
    inBoard->N ^= mask; 
    return N;
  }
  if (inBoard->R & mask)
  {
    inBoard->R ^= mask; 
    return R;
  }
  if (inBoard->P & mask)
  {
    inBoard->P ^= mask; 
    return P;
  }
}

/* findPiece() - This function takes the mask of a location and returns the
 *               type of piece that is on it. */
PIECES findPiece(board * inBoard, unsigned int mask)
{
  debug(1, "entering findPieces()");
  debug(1, "exiting findPieces()");

  if (inBoard->k & mask)
    return k;
  if (inBoard->q & mask)
    return q;
  if (inBoard->b & mask)
    return b;
  if (inBoard->n & mask)
    return n;
  if (inBoard->r & mask)
    return r;
  if (inBoard->p & mask)
    return p;
  if (inBoard->K & mask)
    return K;
  if (inBoard->Q & mask)
    return Q;
  if (inBoard->B & mask)
    return B;
  if (inBoard->N & mask)
    return N;
  if (inBoard->R & mask)
    return R;
  if (inBoard->P & mask)
    return P;
}

/* humanMove() - takes an argument of the form "a1-b2"; that is, a pair of 
 * board coordinates with a dash between them. (Use lowercase only.) The 
 * method decodes the coordinates, checks to see if the move is fully legal, 
 * and then invokes "move" to move the piece. 
 * */

int humanMove(board * inBoard, char * moveString)
{
  char toString[3] = {0};
  char fromString[3] = {0};
  unsigned int toMask = 0;
  unsigned int fromMask = 0;
  PIECES piece;
  std::list<Move> moveList;
  std::list<Move>::const_iterator moveIterator;

  debug(1, "entering humanMove()");

  if (strlen(moveString) != 5)
  {
    printf("Error in humanMove(), input is the wrong lenght.");
    exit(1);
  }
  if (moveString[2] != '-')
  {
    printf("Error in humanMove(), input is of the wrong format.");
    exit(1);
  }

  toString[0] = moveString[3];
  toString[1] = moveString[4];
  fromString[0] = moveString[0];
  fromString[1] = moveString[1];

  toMask = decodeString(toString);
  fromMask = decodeString(fromString);

  piece = findPiece(inBoard, fromMask);

  if (piece == k)
    generate_k_moves(inBoard, &moveList);
  else if (piece == q)
    generate_q_moves(inBoard, &moveList);
  else if (piece == b)
    generate_b_moves(inBoard, &moveList);
  else if (piece == n)
    generate_n_moves(inBoard, &moveList);
  else if (piece == r)
    generate_r_moves(inBoard, &moveList);
  else if (piece == p)
    generate_p_moves(inBoard, &moveList);
  else if (piece == K)
    generate_K_moves(inBoard, &moveList);
  else if (piece == Q)
    generate_Q_moves(inBoard, &moveList);
  else if (piece == B)
    generate_B_moves(inBoard, &moveList);
  else if (piece == N)
    generate_N_moves(inBoard, &moveList);
  else if (piece == R)
    generate_R_moves(inBoard, &moveList);
  else if (piece == P)
    generate_P_moves(inBoard, &moveList);

  moveIterator = moveList.begin();
  // Iterate through list and output each element.
  while (moveIterator != moveList.end())
  {
    if (((*moveIterator).toSquare == toMask) && 
        ((*moveIterator).fromSquare == fromMask))
    {
      move(inBoard, (*moveIterator));
      break;
    }
    moveIterator++;
  }
  if (moveIterator == moveList.end()) //not a valid move
  {
    printf("%s is not a valid move.", moveString);
    exit(1); 
  }
  else //it was a valid move
  {
    debug(1, "exiting humanMove()");
    return 0;
  }
}

/* generateBlackMoves() - This function takes a board and generates all of 
 *                        the possible legal moves that black could make 
 *                        and returns them as an a linked list */
std::list<Move> generateBlackMoves(board * inBoard)
{
  std::list<Move> moveList;

  debug(1, "entering generateBlackMoves()");

  generate_k_moves(inBoard, &moveList); //generate all black king moves
  generate_q_moves(inBoard, &moveList); //generate all black queen moves
  generate_b_moves(inBoard, &moveList); //generate all black bishop moves
  generate_n_moves(inBoard, &moveList); //generate all black night moves
  generate_r_moves(inBoard, &moveList); //generate all black rook moves
  generate_p_moves(inBoard, &moveList); //generate all black pawn moves

  debug(1, "exiting generateBlackMoves()");

  return moveList;
}

/* generateWhiteMoves() - This function takes a board and generates all of 
 *                        the possible legal moves that white could make 
 *                        and returns them as an a linked list */
std::list<Move> generateWhiteMoves(board * inBoard)
{
  std::list<Move> moveList;

  debug(1, "entering generateWhiteMoves()");

  generate_K_moves(inBoard, &moveList); //generate all white king moves
  generate_Q_moves(inBoard, &moveList); //generate all white queen moves
  generate_B_moves(inBoard, &moveList); //generate all white bishop moves
  generate_N_moves(inBoard, &moveList); //generate all white night moves
  generate_R_moves(inBoard, &moveList); //generate all white rook moves
  generate_P_moves(inBoard, &moveList); //generate all white pawn moves

  debug(1, "exiting generateWhiteMoves()");

  return moveList;
}

int generate_k_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->k;
  unsigned int move = 0; 

  debug(1, "entering generate_k_moves");
  
  move = move_n(original);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));
  
  move = move_ne(original);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));

  move = move_nw(original);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));

  move = move_s(original);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));

  move = move_se(original);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));

  move = move_sw(original);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));

  move = move_e(original);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));

  move = move_w(original);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));

  debug(1, "exiting generate_k_moves()");

  return 0;
}

int generate_q_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->q;
  unsigned int move = 0;

  debug(1, "entering generate_q_moves()");

  // north first
  move = move_n(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_n(move);
  }

  // south 
  move = move_s(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_s(move);
  }

  // now east
  move = move_e(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_e(move);
  }

  // west 
  move = move_w(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_w(move);
  }

  // ne 
  move = move_ne(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_ne(move);
  }

  // nw 
  move = move_nw(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_nw(move);
  }

  // now se
  move = move_se(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_se(move);
  }

  // sw last
  move = move_sw(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_sw(move);
  }

  debug(1, "exiting generate_q_moves()");

  return 0;
}

int generate_b_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->b;
  unsigned int move = 0;

  debug(1, "entering generate_b_moves()");

  // ne first
  move = move_ne(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_ne(move);
  }

  // nw next
  move = move_nw(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_nw(move);
  }

  // now se
  move = move_se(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_se(move);
  }

  // sw last
  move = move_sw(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_sw(move);
  }

  debug(1, "exiting generate_b_moves()");

  return 0;
}

int generate_n_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->n;
  unsigned int move = 0;

  debug(1, "entering generate_n_moves()");

  // north first
  move = move_n(original);
  move = move_n(move); 
  move = move_e(move);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));
  move = move_w(move);
  move = move_w(move);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));

  // south next
  move = move_s(original);
  move = move_s(move); 
  move = move_e(move);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));
  move = move_w(move);
  move = move_w(move);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));

  // now east
  move = move_e(original);
  move = move_e(move); 
  move = move_n(move);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));
  move = move_s(move);
  move = move_s(move);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));

  // west last
  move = move_w(original);
  move = move_w(move); 
  move = move_n(move);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));
  move = move_s(move);
  move = move_s(move);
  if (move && !collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));

  debug(1, "exiting generate_n_moves()");

  return 0;
}

int generate_r_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->r;
  unsigned int move = 0;

  debug(1, "entering generate_r_moves()");

  // north first
  move = move_n(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_n(move);
  }

  // south next
  move = move_s(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_s(move);
  }

  // now east
  move = move_e(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_e(move);
  }

  // west last
  move = move_w(original);
  while(move && !collideBlack(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideWhite(inBoard, move))
      break;
    else
      move = move_w(move);
  }

  debug(1, "exiting generate_r_moves()");

  return 0;
}

int generate_p_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->p;
  unsigned int move = 0;

  debug(1, "entering generate_p_moves()");

  move = move_s(original);
  if (move && !collideBlack(inBoard, move) && !collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));

  move = move_se(original);
  if (move && !collideBlack(inBoard, move) && collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));

  move = move_sw(original);
  if (move && !collideBlack(inBoard, move) && collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));

  debug(1, "exiting generate_p_moves()");

  return 0;
}

int generate_K_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->K;
  unsigned int move = 0; 

  debug(1, "entering generate_K_moves()");
  
  move = move_n(original);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));

  move = move_ne(original);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));

  move = move_nw(original);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));

  move = move_s(original);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));

  move = move_se(original);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));

  move = move_sw(original);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));

  move = move_e(original);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));

  move = move_w(original);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));

  debug(1, "exiting generate_K_moves()");

  return 0;
}

int generate_Q_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->Q;
  unsigned int move = 0;

  debug(1, "entering generate_Q_moves()");

  // north first
  move = move_n(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_n(move);
  }

  // south 
  move = move_s(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_s(move);
  }

  // now east
  move = move_e(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_e(move);
  }

  // west 
  move = move_w(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_w(move);
  }

  // ne 
  move = move_ne(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_ne(move);
  }

  // nw 
  move = move_nw(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_nw(move);
  }

  // now se
  move = move_se(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_se(move);
  }

  // sw last
  move = move_sw(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_sw(move);
  }

  debug(1, "exiting generate_Q_moves()");

  return 0;
}

int generate_B_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->B;
  unsigned int move = 0;

  debug(1, "entering generate_B_moves()");

  // ne first
  move = move_ne(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_ne(move);
  }

  // nw next
  move = move_nw(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_nw(move);
  }

  // now se
  move = move_se(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_se(move);
  }

  // sw last
  move = move_sw(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_sw(move);
  }

  debug(1, "exiting generate_B_moves()");

  return 0;
}

int generate_N_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->N;
  unsigned int move = 0;

  debug(1, "entering generate_N_moves()");

  // north first
  move = move_n(original);
  move = move_n(move); 
  move = move_e(move);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));
  move = move_w(move);
  move = move_w(move);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));

  // south next
  move = move_s(original);
  move = move_s(move); 
  move = move_e(move);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));
  move = move_w(move);
  move = move_w(move);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));

  // now east
  move = move_e(original);
  move = move_e(move); 
  move = move_n(move);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));
  move = move_s(move);
  move = move_s(move);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));

  // west last
  move = move_w(original);
  move = move_w(move); 
  move = move_n(move);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));
  move = move_s(move);
  move = move_s(move);
  if (move && !collideWhite(inBoard, move)) 
    moveList->push_back(Move(original, move));  

  debug(1, "exiting generate_N_moves()");

  return 0;
}

int generate_R_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->R;
  unsigned int move = 0;

  debug(1, "entering generate_R_moves()");

  // north first
  move = move_n(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_n(move);
  }

  // south next
  move = move_s(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_s(move);
  }

  // now east
  move = move_e(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_e(move);
  }

  // west last
  move = move_w(original);
  while(move && !collideWhite(inBoard, move))
  {
    moveList->push_back(Move(original, move));
    if (collideBlack(inBoard, move))
      break;
    else
      move = move_w(move);
  }

  debug(1, "exiting generate_R_moves()");

  return 0;
}

int generate_P_moves(board * inBoard, std::list<Move> * moveList)
{
  unsigned int original = inBoard->P;
  unsigned int move = 0;

  debug(1, "entering generate_P_moves()");

  move = move_n(original);
  if (move && !collideWhite(inBoard, move) && !collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));

  move = move_ne(original);
  if (move && !collideWhite(inBoard, move) && collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));

  move = move_nw(original);
  if (move && !collideWhite(inBoard, move) && collideBlack(inBoard, move)) 
    moveList->push_back(Move(original, move));

  debug(1, "exiting generate_P_moves()");

  return 0;
}
/* isGameOver() - This function takes a board and returns 0 if the game is 
 *                not over, a non-negative result if it is. */
int isGameOver(board * inBoard)
{
   debug(1, "entering isGameOver()");
   debug(1, "exiting isGameOver()");

  if (inBoard->moveNumber > 40)
    return 1;
  if (!(inBoard->k) || !(inBoard->K))
    return 1;

  return 0;
}

int move(board * inBoard, Move inMove)
{
  unsigned int to = inMove.toSquare;
  unsigned int from = inMove.fromSquare;
  PIECES piece;

  debug(1, "entering move()");

  if (inBoard->onMove == BLACK && collideBlack(inBoard, to))
  {
    printf("Black collides with black!");
    exit(1);
  }
  
  // some error checking
  if (inBoard->onMove == WHITE && collideWhite(inBoard, to))
  {
    printf("White collides with white!");
    exit(1);
  }
 
  piece = erase(inBoard, from); 
  erase(inBoard, to);

  switch(piece)
  {
    k:
      inBoard->k |= to;
      break;

    q:
      inBoard->q |= to;
      break;
    b:
      inBoard->b |= to;
      break;

    n:
      inBoard->n |= to;
      break;

    r:
      inBoard->r |= to;
      break;

    p:
      inBoard->p |= to;
      break;

    K:
      inBoard->K |= to;
      break;

    Q:
      inBoard->Q |= to;
      break;

    B:
      inBoard->B |= to;
      break;      

    N:
      inBoard->N |= to;
      break;

    R:
      inBoard->R |= to;
      break;

    P:
      inBoard->P |= to;
      break;

    default:
      printf("Error in move, switch hit default!");
      exit(1);
  }

  if (inBoard->onMove == WHITE)
    inBoard->onMove = BLACK;
  else
    inBoard->onMove = WHITE;

  debug(1, "exiting move()");
}

/* for this class of functions, if it would not constitute moving off of the
 * board, we return the bitboard representing the new position. If it would
 * constitute moving off of the board, we return 0
 * */
unsigned int move_n(unsigned int mask)
{
  debug(1, "entering move_n()");

  if (mask & A6 & B6 & C6 & D6 & E6 )
    return 0;
  else
    return mask << 5; 

  debug(1, "exiting move_n()");
}

unsigned int move_s(unsigned int mask)
{
  debug(1, "entering move_s()");

  if (mask & A1 & B1 & C1 & D1 & E1)
    return 0;
  else
    return mask >> 5; 

  debug(1, "exiting move_s()");
}

unsigned int move_e(unsigned int mask)
{
  debug(1, "entering move_e()");

  if (mask & E6 & E5 & E4 & E3 & E2 & E1)
    return 0;
  else
    return mask >> 1;

  debug(1, "exiting move_e()");
}

unsigned int move_w(unsigned int mask)
{
  debug(1, "entering move_w()");

  if (mask & A6 & A5 & A4 & A3 & A2 & A1)
    return 0;
  else
    return mask << 1;

  debug(1, "exiting move_w()");
}

unsigned int move_ne(unsigned int mask)
{
  debug(1, "entering move_ne()");

  if (mask & A6 & B6 & C6 & D6 & E6 & E5 & E4 & E3 & E2 & E1)
    return 0;
  else
    return mask << 4;

  debug(1, "exiting move_ne()");
}

unsigned int move_nw(unsigned int mask)
{
  debug(1, "entering move_nw()");

  if (mask & A1 & A2 & A3 & A4 & A5 & A6 & B6 & C6 & D6 & E6)
    return 0;
  else
    return mask << 6;

  debug(1, "exiting move_nw()");
}

unsigned int move_se(unsigned int mask)
{
  debug(1, "entering move_se()");

  if (mask & A1 & B1 & C1 & D1 & E1 & E2 & E3 & E4 & E5 & E6) 
    return 0;
  else
    return mask << 4;

  debug(1, "exiting move_se()");
}

unsigned int move_sw(unsigned int mask)
{
  debug(1, "entering move_sw()");

  if (mask & A6 & A5 & A4 & A3 & A2 & A1 & B1 & C1 & D1 & E1) 
    return 0;
  else
    return mask << 4;

  debug(1, "exiting move_sw()");
}

int newBoard(board * inBoard)
{
  debug(1, "entering newBoard()");

  /* black pieces */
  inBoard->k = A6; /* king */
  inBoard->q = B6; /* queen(s) */
  inBoard->b = C6; /* bishop */
  inBoard->n = D6; /* night */
  inBoard->r = E6; /* rook */
  inBoard->p = A5 | B5 | C5 | D5 | E5; /* pawn(s) */
  
  /* white pieces */
  inBoard->K = E1; /* king */
  inBoard->Q = D1; /* queen(s) */
  inBoard->B = C1; /* bishop */
  inBoard->N = B1; /* night */
  inBoard->R = A1; /* rook */
  inBoard->P = A2 | B2 | C2 | D2 | E2; /* pawn(s) */

  inBoard->onMove = WHITE;
  inBoard->moveNumber = 1;  

  debug(1, "exiting newBoard()");

  return 0;
}

int printBoard(board * inBoard)
{
  unsigned int seed = A6;
  int space = 0;

  debug(1, "entering printBoard()");

  printf("%i", inBoard->moveNumber);

  if (inBoard->onMove == WHITE)
    printf(" W");
  else
    printf(" B");

  while (seed)
  {
    if (space % 5 == 0)
      printf("\n");
    
    printf ("%c", returnPiece(inBoard, seed));
    seed = seed >> 1; 

    space++;
  }

  printf("\n");

  debug(1, "exiting printBoard()");

  return 0;
}


/*
 * returnPiece() - This function takes a board and a mask to print. If any of 
 *                 the pieces correspond to the mask, their character is 
 *                 returned.
 **/

char returnPiece(board * inBoard, unsigned int mask)
{
  debug(1, "entering returnPiece()");
  debug(1, "exiting returnPiece()");

  /* black pieces */
  if(inBoard->k & mask) /* king */
    return 'k';
  if(inBoard->q & mask) /* queen(s) */
    return 'q';
  if(inBoard->b & mask) /* bishop */
    return 'b';
  if(inBoard->n & mask) /* night */
    return 'n';
  if(inBoard->r & mask) /* rook */
    return 'r';
  if(inBoard->p & mask) /* pawn(s) */
    return 'p';
  
  /* white pieces */
  if(inBoard->K & mask) /* king */
    return 'K';
  if(inBoard->Q & mask) /* queen(s) */
    return 'Q';
  if(inBoard->B & mask) /* bishop */
    return 'B';
  if(inBoard->N & mask) /* night */
    return 'N';
  if(inBoard->R & mask) /* rook */
    return 'R';
  if(inBoard->P & mask) /* pawn(s) */
    return 'P';

  return '.'; /* if we get here, it must be a blank space */
}

